[v1.x] fix: handle ClosedResourceError when transport closes mid-request#2334
Conversation
Backports fixes from #2306 to v1.x to address issue #2328. When the transport closes while handlers are processing requests (e.g., stdin EOF during a long-running tool call), the server could crash with ClosedResourceError when trying to send a response through the already-closed write stream. This fix: 1. Wraps the message loop in a try/finally that cancels in-flight handlers when the transport closes, preventing them from attempting to respond 2. Catches BrokenResourceError and ClosedResourceError when calling message.respond() and logs instead of crashing 3. Properly re-raises transport-close cancellation to let the task group handle it (vs client-initiated cancellation which already sent a response) 4. Uses list() snapshot when iterating _response_streams in the finally block to avoid 'dictionary changed size during iteration' errors Fixes #2328
- Hoist SessionMessage/types imports from function bodies to module level - Add dict[str, Any] type arguments to satisfy pyright strict mode
|
@owendevereaux @maxisbey This issue was not correctly fixed. Bellow is report what is wrong, I'll add issue for it too: Bug:
|
Summary
Backports fixes from #2306 to v1.x to address issue #2328.
When the transport closes while handlers are processing requests (e.g., stdin EOF during a long-running tool call, or a malicious client sending invalid UTF-8 bytes that crashes the transport), the server could crash with
ClosedResourceErrorwhen trying to send a response through the already-closed write stream.Changes
list()snapshot when iterating_response_streamsto avoid 'dictionary changed size during iteration' errorsTesting
Added two new test cases that reproduce the crash scenarios:
test_server_cancels_in_flight_handlers_on_transport_closetest_server_handles_transport_close_with_pending_server_to_client_requestsAll existing tests continue to pass.
Fixes #2328